package com.yunxin.yundubbo.config;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.yunxin.yundubbo.AutoConfiguration;
import com.yunxin.yundubbo.connection.DubboClient;
import com.yunxin.yundubbo.interfaces.DubboReference;
import com.yunxin.yundubbo.interfaces.DubboService;
import com.yunxin.yundubbo.mode.Message;
import com.yunxin.yundubbo.util.*;
import io.netty.channel.Channel;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.*;
import java.net.InetAddress;
import java.util.*;
import java.util.concurrent.*;


@Component
public class DubboBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    protected static final Log logger = LogFactory.getLog(DubboBeanPostProcessor.class);

    private final AutoConfiguration autoConfiguration;


    public DubboBeanPostProcessor(AutoConfiguration autoConfiguration) {
        this.autoConfiguration = autoConfiguration;
    }

    /**
     * 动态生成可注入动态代理类
     */
    private final ConcurrentHashMap<String, DubboReferenceFieldElement> cache = new ConcurrentHashMap<>();


    /**
     * 把依赖注入到字段、setter 中
     *
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        Class<?> targetClass = bean.getClass();
        List<DubboReferenceFieldElement> elements = memberList(targetClass);
        if (CollectionUtils.isEmpty(elements)) {
            return pvs;
        }
        for (DubboReferenceFieldElement element : elements) {
            DubboReferenceFieldElement cached = cache.computeIfAbsent(element.className, key -> {
                element.object = element.proxy();
                return element;
            });
            Field field = element.field;
            ReflectionUtils.makeAccessible(field);
            try {
                field.set(bean, cached.object);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
        return pvs;
    }


    private List<DubboReferenceFieldElement> memberList(Class<?> targetClass) {
        List<DubboReferenceFieldElement> arrayList = new ArrayList<>();
        ReflectionUtils.doWithLocalFields(targetClass, field -> {
            MergedAnnotation<?> ann = findDubboReferenceAnnotation(field);
            if (ann != null) {
                if (Modifier.isStatic(field.getModifiers())) {
                    if (logger.isInfoEnabled()) {
                        logger.info("DubboReference annotation is not supported on static fields: " + field);
                    }
                } else {
                    arrayList.add(new DubboReferenceFieldElement(field, NamingServiceContext.FUTURE));
                }
            }
        });
        return arrayList;
    }

    private MergedAnnotation<?> findDubboReferenceAnnotation(AccessibleObject ao) {
        MergedAnnotations annotations = MergedAnnotations.from(ao);
        MergedAnnotation<?> annotation = annotations.get(DubboReference.class);
        if (annotation.isPresent()) {
            return annotation;
        }
        return null;
    }

    /**
     * 调用构造函数创建 Bean 对象，还没有属性注入
     *
     * @param bean
     * @param beanName
     * @throws BeansException
     */
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if (ObjectUtil.isNotNull(bean)) {
            Class<?> aClass = bean.getClass();
            if (aClass.isAnnotationPresent(DubboService.class)) {
                Class<?>[] classInterfaces = aClass.getInterfaces();
                if (ArrayUtil.isNotEmpty(classInterfaces)) {
                    for (Class<?> anInterface : classInterfaces) {
                        ExposeInterfacesContext.set(anInterface.getName());
                    }
                }
            }
        }
        return InstantiationAwareBeanPostProcessor.super.postProcessAfterInstantiation(bean, beanName);
    }

//    @Override
//    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
//        return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInstantiation(beanClass, beanName);
//    }

    private static class DubboReferenceFieldElement {

        private Class<?> aClass;

        private Field field;

        private String className;

        private volatile Object object;

        private CompletableFuture<NamingService> future;

        private DubboReferenceFieldElement(Field field, CompletableFuture<NamingService> future) {
            this.field = field;
            this.className = field.getType().getName();
            this.aClass = field.getType();
            this.future = future;
        }

        public Object proxy() {
            if (object == null) {
                logger.info("开始创建动态代理类！");
                synchronized (this) {
                    if (object == null) {
                        object = Proxy.newProxyInstance(aClass.getClassLoader(), new Class[]{aClass}, new InvocationHandler() {
                            @Override
                            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                CompletableFuture<Object> supplyAsync = CompletableFuture.supplyAsync(() -> {
                                    try {
                                        Channel channel = ChannelCacheUtil.getCacheHandler(className);
                                        if (channel == null || !channel.isActive()) {
                                            Instance instance = future.get().selectOneHealthyInstance(className);
                                            DubboClient client = DubboClient.getInstance();
                                            InetAddress localHost = InetAddress.getLocalHost();
                                            channel = client.doConnectSync(localHost.getHostAddress(), instance.getPort(), className);
                                        }
                                        if (channel == null) {
                                            throw new RuntimeException("netty channel is null!");
                                        }

                                        String requestId = UUID.randomUUID().toString();
                                        JSONObject jsonObject = new JSONObject();
                                        Parameter[] parameters = method.getParameters();
                                        for (int i = 0; i < parameters.length; i++) {
                                            jsonObject.put(parameters[i].getName(), args[i]);
                                        }

                                        String data = jsonObject.toString();
                                        CompletableFuture<String> future = new CompletableFuture<>();
                                        RequestContext.set(requestId, future);

                                        channel.writeAndFlush(Message.send(className, data, method.getName(), requestId));

                                        try {
                                            String val = future.get(6, TimeUnit.SECONDS);
                                            // 优化类型转换逻辑
                                            return ResponseConverter.convertResponseValue(val, method);
                                        } catch (Exception e) {
                                            throw new RuntimeException("RPC call failed: " + e.getMessage(), e);
                                        }
                                    } catch (Exception e) {
                                        throw new RuntimeException("RPC execution failed: " + e.getMessage(), e);
                                    }
                                });

                                try {
                                    return supplyAsync.get(6, TimeUnit.SECONDS);
                                } catch (TimeoutException e) {
                                    throw new RuntimeException("RPC call timeout", e);
                                } catch (ExecutionException e) {
                                    throw new RuntimeException("RPC execution failed", e);
                                } catch (InterruptedException e) {
                                    Thread.currentThread().interrupt();
                                    throw new RuntimeException("RPC call interrupted", e);
                                }
                            }
                        });
                    }
                }
            }
            return object;
        }

        private static class ResponseConverter {

            /**
             * 根据方法返回类型转换响应值
             */
            public static Object convertResponseValue(String value, Method method) {
                if (value == null) {
                    return null;
                }

                Type returnType = method.getGenericReturnType();
                Class<?> returnClass = method.getReturnType();

                try {
                    // 1. 返回类型是String，直接返回
                    if (returnClass == String.class) {
                        return value;
                    }

                    // 2. 基本类型及其包装类处理
                    if (returnClass.isPrimitive() || isWrapperType(returnClass)) {
                        return parseBasicType(value, returnClass);
                    }

                    // 3. 集合类型处理
                    if (Collection.class.isAssignableFrom(returnClass)) {
                        return parseCollection(value, returnType, returnClass);
                    }

                    // 4. 数组类型处理
                    if (returnClass.isArray()) {
                        return parseArray(value, returnType, returnClass);
                    }

                    // 5. Map类型处理
                    if (Map.class.isAssignableFrom(returnClass)) {
                        return parseMap(value, returnType, returnClass);
                    }

                    // 6. 自定义对象类型
                    return JSON.parseObject(value, returnType);

                } catch (Exception e) {
                    throw new RuntimeException("Type conversion failed for type: " + returnType + ", value: " + value, e);
                }
            }

            /**
             * 解析基本类型
             */
            private static Object parseBasicType(String value, Class<?> targetClass) {
                if (targetClass == int.class || targetClass == Integer.class) {
                    return Integer.parseInt(value);
                } else if (targetClass == long.class || targetClass == Long.class) {
                    return Long.parseLong(value);
                } else if (targetClass == double.class || targetClass == Double.class) {
                    return Double.parseDouble(value);
                } else if (targetClass == float.class || targetClass == Float.class) {
                    return Float.parseFloat(value);
                } else if (targetClass == boolean.class || targetClass == Boolean.class) {
                    return Boolean.parseBoolean(value);
                } else if (targetClass == byte.class || targetClass == Byte.class) {
                    return Byte.parseByte(value);
                } else if (targetClass == short.class || targetClass == Short.class) {
                    return Short.parseShort(value);
                } else if (targetClass == char.class || targetClass == Character.class) {
                    return value.charAt(0);
                }
                return value;
            }

            /**
             * 解析集合类型
             */
            private static Object parseCollection(String value, Type returnType, Class<?> returnClass) {
                // 获取集合的泛型类型
                Type elementType = getCollectionElementType(returnType);

                // 使用TypeReference来保持泛型信息
                if (returnClass == List.class) {
                    return JSON.parseObject(value, new TypeReference<List<Object>>() {}.getType());
                } else if (returnClass == Set.class) {
                    return JSON.parseObject(value, new TypeReference<Set<Object>>() {}.getType());
                } else {
                    // 其他集合类型
                    return JSON.parseObject(value, returnType);
                }
            }

            /**
             * 解析数组类型
             */
            private static Object parseArray(String value, Type returnType, Class<?> returnClass) {
                Class<?> componentType = returnClass.getComponentType();

                if (componentType == String.class) {
                    return JSON.parseObject(value, String[].class);
                } else if (componentType == Integer.class || componentType == int.class) {
                    return JSON.parseObject(value, Integer[].class);
                } else if (componentType == Long.class || componentType == long.class) {
                    return JSON.parseObject(value, Long[].class);
                } else {
                    // 其他类型数组
                    return JSON.parseObject(value, returnType);
                }
            }

            /**
             * 解析Map类型
             */
            private static Object parseMap(String value, Type returnType, Class<?> returnClass) {
                return JSON.parseObject(value, returnType);
            }

            /**
             * 判断是否是包装类型
             */
            private static boolean isWrapperType(Class<?> clazz) {
                return clazz == Integer.class || clazz == Long.class ||
                        clazz == Double.class || clazz == Float.class ||
                        clazz == Boolean.class || clazz == Byte.class ||
                        clazz == Short.class || clazz == Character.class;
            }

            /**
             * 获取集合元素的泛型类型
             */
            private static Type getCollectionElementType(Type collectionType) {
                if (collectionType instanceof ParameterizedType) {
                    ParameterizedType paramType = (ParameterizedType) collectionType;
                    Type[] typeArgs = paramType.getActualTypeArguments();
                    if (typeArgs.length > 0) {
                        return typeArgs[0];
                    }
                }
                return Object.class;
            }
        }

    }
}
